package com.hooya.fa.eu.biz.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hooya.fa.eu.api.bo.*;
import com.hooya.fa.eu.api.util.MD5Util;
import com.hooya.fa.eu.biz.dao.entity.StkOriginCollect;
import com.hooya.fa.eu.biz.dao.entity.TradeRecord;
import com.hooya.fa.eu.biz.dao.manager.special.TradeRecordB2bManager;
import com.hooya.fa.eu.biz.dao.manager.special.TradeRecordCgManager;
import com.hooya.fa.eu.biz.dao.mapper.MetaRelationMapper;
import com.hooya.fa.eu.biz.dao.mapper.TradeRecordMapper;
import com.hooya.fa.eu.biz.dao.mapper.stk.StkOrigCollectMapper;
import com.hooya.fa.eu.biz.service.EuSourceDataService;
import com.hooya.fa.eu.biz.service.TradeRecordService;
import com.hooya.integrated.common.core.util.BeanCopyUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.hooya.fa.eu.api.util.DateExtUtil.getYesterday;

/**
 * @Description 买卖记录
 * @Author : Zongz
 * @Copyright Copyright (c) 豪雅集团
 * @Create 2023/11/28
 * @Version 1.0.0
 */
@Slf4j
@Service
@DS("fa_eu")
@AllArgsConstructor
public class TradeRecordServiceImpl extends ServiceImpl<TradeRecordMapper, TradeRecord> implements TradeRecordService {

    private final EuSourceDataService euSourceDataService;

    private final TradeRecordB2bManager tradeRecordB2bManager;

    private final TradeRecordCgManager tradeRecordCgManager;

    private final TradeRecordMapper tradeRecordMapper;

    private final StkOrigCollectMapper stkOrigCollectMapper;

    private final MetaRelationMapper metaRelationMapper;

    @Override
    @DSTransactional
    public void getB2bData(String startDate, String endDate) {
        long start = System.currentTimeMillis();
        //买卖记录（含价格和海运费）
        List<TradeRecordHisBO> historyList = tradeRecordMapper.getMmHisBoListByDate(startDate, endDate);
        //所有历史价格
        List<LastCostBO> costHisList = euSourceDataService.getMmList();
        Map<String, LastCostBO> hisMap = costHisList.stream()
                .collect(Collectors.toMap(LastCostBO::getCpbh, i -> i, (k1, k2) -> k1));
        //买卖记录
        List<TradeRecord> recordList = tradeRecordMapper.getMmListByDate(startDate, endDate);
        //组装差集数据
        tradeRecordB2bManager.getHisDifferentialData(historyList, hisMap, recordList);
        //获取主数据源（mmjl）
        List<TradeRecordBO> recordBoList = tradeRecordMapper.getB2bBoListByDate(startDate, endDate);
        if (CollectionUtils.isEmpty(recordBoList)) {
            return;
        }
        //设置买家卖家
        tradeRecordB2bManager.setBuyerSeller(recordBoList);
        //修改tocampany的fds、costway拼接为处理后的买家税号
        tradeRecordB2bManager.resolveTocompany(recordBoList);
        //填充数据，得出最终数据
        List<StkOriginCollect> res = tradeRecordB2bManager.fillB2BData(recordBoList, startDate, historyList);
        log.info("B2B 最终数据共为：" + res.size() + "条, 用时为：" + (System.currentTimeMillis() - start) / 1000 + "s");
//        ((TradeRecordService) AopContext.currentProxy()).batchInsertSkt(res);
    }

    @Override
    @DSTransactional
    public void getB2cData(String startDate, String endDate) {
        long start = System.currentTimeMillis();
        //主数据源
        List<SellRecordBO> b2cBoList = tradeRecordMapper.getB2cBoListByDate(startDate, endDate);
        //波兰价格数据
        List<SellPriceBO> plnPriceList = euSourceDataService.getPlnPrice();
        //欧洲价格数据
        List<SellPriceBO> eurPriceList = euSourceDataService.getEurPrice();
        Map<String, SellPriceBO> plPriceMap = plnPriceList.stream()
                .collect(Collectors.toMap(SellPriceBO::getNumber, i -> i));
        Map<String, SellPriceBO> euPriceMap = eurPriceList.stream()
                .collect(Collectors.toMap(
                        item -> item.getOrderId() + "-" + item.getCpbh(),  // 合并 'orderid' 和 'cpbh' 作为唯一键
                        Function.identity(),
                        (existing, replacement) -> existing // 如果遇到重复键，保留第一个
                ));

        //结果集合
        List<StkOriginCollect> res = new LinkedList<>();
        Set<String> otherOrderIdList = new HashSet<>();

        //遍历主数据源，处理对比价格(1.波兰价格，2.欧洲价格)
        b2cBoList.forEach(l -> {
            StkOriginCollect data = BeanCopyUtils.turnToVO(l, StkOriginCollect.class);
            //价格处理
            SellPriceBO plPrice = plPriceMap.get(l.getSheetNumber());
            if (Objects.nonNull(plPrice)) {
                //检查 plPrice.getPrice() 是否非 null 且不等于 0 设置国家为PLN、价格，添加到结果中
                if (Objects.nonNull(plPrice.getPrice()) && plPrice.getPrice().compareTo(0D) != 0) {
                    data.setCurrency("PLN");
                    data.setPrice(plPrice.getPrice());
                    res.add(data);
                    return;
                }
            }
            SellPriceBO euPrice = euPriceMap.get(l.getOrderId() + l.getCpbh());
            if (Objects.nonNull(euPrice)) {
                if (Objects.nonNull(euPrice.getPrice()) && euPrice.getPrice().compareTo(0D) != 0) {
                    data.setCurrency("EUR");
                    data.setPrice(plPrice.getPrice());
                    res.add(data);
                    return;
                }
            }
            //没有价格
            otherOrderIdList.add(l.getOrderId());
        });
        //处理匹配不到波兰、欧盟价格数据的销售数据(temp_xsjl)，再去xsjl_2303中寻找然后赋值
        if (!CollectionUtils.isEmpty(otherOrderIdList)) {
            //其他价格（一般都是数据组导入的数据）
            List<SellPriceBO> otherPriceList = euSourceDataService.getOtherPrice(otherOrderIdList);
            Map<String, SellRecordBO> sheetnumberMap = b2cBoList.stream()
                    .collect(Collectors.toMap(SellRecordBO::getSheetNumber, i -> i));
            for (SellPriceBO bo : otherPriceList) {
                SellRecordBO sell = sheetnumberMap.get(bo.getNumber());
                if (Objects.nonNull(sell) && sell.getPrice().compareTo(0D) != 0) {
                    StkOriginCollect data = BeanCopyUtils.turnToVO(sell, StkOriginCollect.class);
                    data.setCurrency(bo.getCurrency());
                    data.setPrice(bo.getPrice());
                    res.add(data);
                }
            }
        }
        if (b2cBoList.size() != res.size()) {
            throw new RuntimeException("b2c数据不齐，相差" + (b2cBoList.size() - res.size()) + "条");
        }
        log.info("B2C 最终数据共为：" + res.size() + "条, 用时为：" + (System.currentTimeMillis() - start) / 1000 + "s");
//        ((TradeRecordService) AopContext.currentProxy()).batchInsertSkt(res);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getBsData(String startDate, String endDate) {
        long start = System.currentTimeMillis();
        //获取主数据源
        List<LossesBO> lossesList = tradeRecordMapper.getBsBoListByDate(startDate, endDate);
        //获取关税
        List<MetaStkCustomsBO> metaStkCustomsBOList = metaRelationMapper.getListByCondition(getYesterday(endDate));
        //结果集合
        List<StkOriginCollect> res = new LinkedList<>();
        Map<String, Long> stkCustomsSizeMap = metaStkCustomsBOList.stream()
                .collect(Collectors.groupingBy(l -> l.getSku() + l.getBelongs(), Collectors.counting()));
        Map<String, List<MetaStkCustomsBO>> stkCustomsBoMap = metaStkCustomsBOList.stream()
                .collect(Collectors.groupingBy(MetaStkCustomsBO::getSku));
        lossesList.forEach(l -> {
            StkOriginCollect data = BeanCopyUtils.turnToVO(l, StkOriginCollect.class);
            dealWithPrice(data, stkCustomsSizeMap, stkCustomsBoMap, l.getCpbh(), l.getAbbrbelongs());
            res.add(data);
        });
        log.info("B2C 最终数据共为：" + res.size() + "条, 用时为：" + (System.currentTimeMillis() - start) + "ms");
//        ((TradeRecordService) AopContext.currentProxy()).batchInsertSkt(res);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getCgData(String startDate, String endDate) {
        long start = System.currentTimeMillis();
        //主数据源（含价格）
        List<PurchaseBO> purchaseList = tradeRecordMapper.getCgBoListByDate(startDate, endDate);
        tradeRecordCgManager.suppleInformation(purchaseList);
        List<StkOriginCollect> res = BeanCopyUtils.turnToVO(purchaseList, StkOriginCollect.class);
        log.info("CG 最终数据共为：" + res.size() + "条, 用时为：" + (System.currentTimeMillis() - start) + "ms");
//        ((TradeRecordService) AopContext.currentProxy()).batchInsertSkt(res);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void getThData(String startDate, String endDate) {
        long start = System.currentTimeMillis();
        List<ReturnedGoodsBO> returnedGoodsList = tradeRecordMapper.getThBoListByDate(startDate, endDate);
        //获取关税
        List<MetaStkCustomsBO> metaStkCustomsBOList = metaRelationMapper.getListByCondition(getYesterday(endDate));
        Map<String, Long> stkCustomsSizeMap = metaStkCustomsBOList.stream()
                .collect(Collectors.groupingBy(l -> l.getSku() + l.getBelongs(), Collectors.counting()));
        Map<String, List<MetaStkCustomsBO>> stkCustomsBoMap = metaStkCustomsBOList.stream()
                .collect(Collectors.groupingBy(MetaStkCustomsBO::getSku));
        //结果集合
        List<StkOriginCollect> res = new LinkedList<>();
        returnedGoodsList.forEach(l -> {
            StkOriginCollect data = BeanCopyUtils.turnToVO(l, StkOriginCollect.class);
            dealWithPrice(data, stkCustomsSizeMap, stkCustomsBoMap, l.getCpbh(), l.getAbbrbelongs());
            res.add(data);
        });
        log.info("TH 最终数据共为：" + res.size() + "条, 用时为：" + (System.currentTimeMillis() - start) + "ms");
//        ((TradeRecordService) AopContext.currentProxy()).batchInsertSkt(res);
    }

    @Override
    @DSTransactional
    public void getZyData(String startDate, String endDate) {
        long start = System.currentTimeMillis();
        List<TransshipBO> transshipList = tradeRecordMapper.getZyBoListByDate(startDate, endDate);
        //买卖记录（含价格和海运费）
        List<TradeRecordHisBO> historyList = tradeRecordMapper.getZyHisBoListByDate(startDate, endDate);
        //所有历史价格
        List<LastCostBO> costHisList = euSourceDataService.getZyList();
        Map<String, LastCostBO> hisMap = costHisList.stream().collect(Collectors.toMap(LastCostBO::getCpbh, i -> i, (k1, k2) -> k1));
        //买卖记录
        List<TradeRecord> recordList = tradeRecordMapper.getZyListByDate(startDate, endDate);
        //组装差集数据
        tradeRecordB2bManager.getHisDifferentialData(historyList, hisMap, recordList);
        //获取关税
        List<MetaStkCustomsBO> metaStkCustomsBOList = metaRelationMapper.getListByCondition4Zy(startDate, endDate);
        //数据准备
        Map<String, TradeRecordHisBO> dealHisMap = historyList.stream().collect(Collectors.toMap(TradeRecordHisBO::getCpbh, i -> i));
        Map<String, Long> stkCustomsSizeMap = metaStkCustomsBOList.stream()
                .collect(Collectors.groupingBy(l -> l.getSku() + l.getBelongs(), Collectors.counting()));
        Map<String, List<MetaStkCustomsBO>> stkCustomsBoMap = metaStkCustomsBOList.stream()
                .collect(Collectors.groupingBy(MetaStkCustomsBO::getSku));
        //结果集
        List<StkOriginCollect> res = new LinkedList<>();
        transshipList.forEach(l -> {
            //设置海运费
            StkOriginCollect data = BeanCopyUtils.turnToVO(l, StkOriginCollect.class);
            if (Objects.nonNull(dealHisMap.get(l.getCpbh()))) {
                data.setOceanFee(dealHisMap.get(l.getCpbh()).getOceanFee());
            } else {
                log.error(l.toString());
                throw new RuntimeException("产品编号【" + l.getCpbh() + "】无海运费信息!");
            }
            //设置id
            String idStr = startDate + l.getHthm() + l.getFromcompany() + l.getTocompany() +
                    l.getFromCountry() + l.getToCountry();
            data.setInvoiceId(MD5Util.sec4md5(idStr));
            //设置价格，货币国家，开票日期
            dealWithPrice(data, stkCustomsSizeMap, stkCustomsBoMap, l.getCpbh(), l.getAbbrbelongs());
            //出口日期
            data.setExportPrice(data.getPrice());
            res.add(data);
        });
        log.info("ZY 最终数据共为：" + res.size() + "条, 用时为：" + (System.currentTimeMillis() - start) + "ms");
//        ((TradeRecordService) AopContext.currentProxy()).insertBatchSomeColumnStk(res);
    }

    /**
     * 处理价格，发货地，发票日期
     *
     * @param data              数据结果
     * @param stkCustomsSizeMap 货权条数信息
     * @param stkCustomsBoMap   货权信息
     * @param sku               产品编号
     * @param abbrBelongs       货权归属
     */
    public void dealWithPrice(StkOriginCollect data, Map<String, Long> stkCustomsSizeMap,
                              Map<String, List<MetaStkCustomsBO>> stkCustomsBoMap,
                              String sku, String abbrBelongs) {
        Long size = stkCustomsSizeMap.get(sku + abbrBelongs);
        if (Objects.isNull(size)) {
            //该产品编号，没有该货权地，所以数据应该只会有一条
            List<MetaStkCustomsBO> onlyOne = stkCustomsBoMap.get(sku);
            if (!CollectionUtils.isEmpty(onlyOne)) {
                data.setPrice(onlyOne.get(0).getPrice());
                data.setCurrency(onlyOne.get(0).getCurrency());
                data.setInvoiceDate(onlyOne.get(0).getInvoiceDate());
            } else {
                log.info("产品编号为：【" + data.getSku() + "】无出口价格");
            }
        } else {
            //通常情况下，根据产品编号取，会有2条货权
            if (CollectionUtils.isEmpty(stkCustomsBoMap.get(sku))) {
                log.info("产品编号为：【" + sku + "】无出口价格");
            } else {
                List<MetaStkCustomsBO> twoDataCustoms = stkCustomsBoMap.get(sku)
                        .stream().filter(c -> c.getBelongs().equals(abbrBelongs)).collect(Collectors.toList());
                data.setPrice(twoDataCustoms.get(0).getPrice());
                data.setCurrency(twoDataCustoms.get(0).getCurrency());
                data.setInvoiceDate(twoDataCustoms.get(0).getInvoiceDate());
            }
        }
    }

    @Override
    public void insertBatchSomeColumnStk(List<StkOriginCollect> res) {
        if (!CollectionUtils.isEmpty(res)) {
            //以20000为跨度分，共分几次
            int partialLimit = res.size() / 20000 + 1;
            //分partialLimit次，每次具体可以分到的条数
            int limit = (res.size() + partialLimit - 1) / partialLimit;
            List<List<StkOriginCollect>> splitList = Stream.iterate(0, n -> n + 1)
                    .limit(partialLimit).parallel()
                    .map(a -> res.stream().skip((long) a * limit).limit(limit)
                            .parallel().collect(Collectors.toList())).collect(Collectors.toList());
            for (List<StkOriginCollect> list : splitList) {
                stkOrigCollectMapper.insertBatchSomeColumn(list);
            }
        }
    }

}
